﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NUnit.Framework;
using NUnit.Mocks;

using Working.Domínio.Produtos;

namespace Working.Domínio.Produtos.Teste
{
    [TestFixture]
    public class TesteCatálogoDeProdutos
    {
        private DynamicMock produtoDataMock;

        [SetUp]
        public void InicializaTeste()
        {
            produtoDataMock = new DynamicMock(typeof(IProdutoDataAdapter));
        }

        [Test]
        public void TestaConstrutor()
        {
            CatalogoDeProdutos catálogo = new CatalogoDeProdutos();
            Assert.AreEqual(string.Empty, catálogo.Identificação);            
        }

        [Test]
        public void TestaPropriedades()
        {
            string identificação = "000-555-02";
            
            CatalogoDeProdutos catálogo = new CatalogoDeProdutos();
            catálogo.Identificação = identificação;

            Assert.AreEqual(identificação, catálogo.Identificação);
        }


        [Test]
        [ExpectedException(typeof(WorkingException))]
        public void TestaObterProdutoSemAdaptador()
        {
            ItemID id = new ItemID("987645655");
            CatalogoDeProdutos catálogo = new CatalogoDeProdutos();
            Produto produto = catálogo.ObterProduto(id);
        }

        [Test]
        public void TestaObterProdutoComAdaptador()
        {
            ItemID id1 = new ItemID("987654");
            Produto produtoRetorno1 = new Produto(id1, "Caneta", 1.95M);

            ItemID id2 = new ItemID("123456");
            Produto produtoRetorno2 = new Produto(id2, "Borracha", .05M);

            ItemID id3 = new ItemID("147258");
            Produto produtoRetorno3 = new Produto(id3, "Lápis", .15M);

            ItemID id4 = new ItemID("963852");
            Produto produtoRetorno4 = new Produto(id4, "Caderno", 16M);

            ItemID id5 = new ItemID("582460");
            Produto produtoRetorno5 = new Produto(id5, "Fichário", 15M);
            

            //Configura simulador de dados
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno1, id1);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno2, id2);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno3, id3);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno4, id4);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno5, id5);

            CatalogoDeProdutos catálogo = new CatalogoDeProdutos((IProdutoDataAdapter)
                produtoDataMock.MockInstance);

            Produto produto1 = catálogo.ObterProduto(id1);
            Produto produto2 = catálogo.ObterProduto(id2);
            Produto produto3 = catálogo.ObterProduto(id3);
            Produto produto4 = catálogo.ObterProduto(id4);
            Produto produto5 = catálogo.ObterProduto(id5);

            Assert.AreEqual(produtoRetorno1, produto1);
            Assert.AreEqual(produtoRetorno2, produto2);
            Assert.AreEqual(produtoRetorno3, produto3);
            Assert.AreEqual(produtoRetorno4, produto4);
            Assert.AreEqual(produtoRetorno5, produto5);           

            produtoDataMock.Verify();
        }

        [Test]
        public void TestaObterProdutoItemIDString()
        {
            string id1 = "987654";
            Produto produtoRetorno1 = new Produto(id1, "Caneta", 1.95M);

            string id2 = "123456";
            Produto produtoRetorno2 = new Produto(id2, "Borracha", .05M);

            string id3 = "147258";
            Produto produtoRetorno3 = new Produto(id3, "Lápis", .15M);

            string id4 = "963852";
            Produto produtoRetorno4 = new Produto(id4, "Caderno", 16M);

            string id5 = "582460";
            Produto produtoRetorno5 = new Produto(id5, "Fichário", 15M);


            //Configura simulador de dados
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno1, new ItemID(id1));
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno2, new ItemID(id2));
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno3, new ItemID(id3));
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno4, new ItemID(id4));
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno5, new ItemID(id5));

            CatalogoDeProdutos catálogo = new CatalogoDeProdutos((IProdutoDataAdapter)
                produtoDataMock.MockInstance);

            Produto produto1 = catálogo.ObterProduto(id1);
            Produto produto2 = catálogo.ObterProduto(id2);
            Produto produto3 = catálogo.ObterProduto(id3);
            Produto produto4 = catálogo.ObterProduto(id4);
            Produto produto5 = catálogo.ObterProduto(id5);

            Assert.AreEqual(produtoRetorno1, produto1);
            Assert.AreEqual(produtoRetorno2, produto2);
            Assert.AreEqual(produtoRetorno3, produto3);
            Assert.AreEqual(produtoRetorno4, produto4);
            Assert.AreEqual(produtoRetorno5, produto5);

            produtoDataMock.Verify();
        }

        [Test]
        public void TestaObterProdutoComIDInexistente()
        {
            ItemID id = new ItemID("951753");

            //Configura simulador de dados
            produtoDataMock.ExpectAndReturn("ObterProduto", null, id);

            CatalogoDeProdutos catálogo = new CatalogoDeProdutos((IProdutoDataAdapter)
                produtoDataMock.MockInstance);

            Produto produto = catálogo.ObterProduto(id);
            Assert.AreEqual(null, produto);
            produtoDataMock.Verify();
        }

        [Test]
        public void TestaObterProdutoCacheInterno()
        {
            ItemID id1 = new ItemID("987654");
            Produto produtoRetorno1 = new Produto(id1, "Caneta", 1.95M);

            ItemID id2 = new ItemID("123456");
            Produto produtoRetorno2 = new Produto(id2, "Borracha", .05M);

            ItemID id3 = new ItemID("147258");
            Produto produtoRetorno3 = new Produto(id3, "Lápis", .15M);

            ItemID id4 = new ItemID("963852");
            Produto produtoRetorno4 = new Produto(id4, "Caderno", 16M);

            ItemID id5 = new ItemID("582460");
            Produto produtoRetorno5 = new Produto(id5, "Fichário", 15M);

            //Configura simulador de dados
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno1, id1);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno2, id2);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno3, id3);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno4, id4);
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno5, id5);

            CatalogoDeProdutos catálogo = new CatalogoDeProdutos((IProdutoDataAdapter)
                produtoDataMock.MockInstance);

            //Primeira busca de produtos carrega o cache interno
            Produto produto1 = catálogo.ObterProduto(id1);
            Produto produto2 = catálogo.ObterProduto(id2);
            Produto produto3 = catálogo.ObterProduto(id3);
            Produto produto4 = catálogo.ObterProduto(id4);
            Produto produto5 = catálogo.ObterProduto(id5);

            produtoDataMock.Verify();

            //Na segunda busca por produto, o adaptador de dados não deverá ser invocado,
            //buscando o produto no cache interno
            produtoDataMock.ExpectNoCall("ObterProduto");

            produto1 = catálogo.ObterProduto(id1);
            produto2 = catálogo.ObterProduto(id2);
            produto3 = catálogo.ObterProduto(id3);
            produto4 = catálogo.ObterProduto(id4);
            produto5 = catálogo.ObterProduto(id5);

            produtoDataMock.Verify();
        }

        [Test]
        [ExpectedException(typeof(WorkingException))]
        public void TestaObterProdutoComIDInválido()
        {
            //Identificador do produto é passado como parâmetro para busca mas 
            //não é vinculado ao produto
            ItemID id1 = new ItemID("987654");
            Produto produtoRetorno1 = new Produto(new ItemID(string.Empty), "Caneta", 1.95M);            

            //Configura simulador de dados
            produtoDataMock.ExpectAndReturn("ObterProduto", produtoRetorno1, id1);

            CatalogoDeProdutos catálogo = new CatalogoDeProdutos((IProdutoDataAdapter)
                produtoDataMock.MockInstance);

            Produto produto1 = catálogo.ObterProduto(id1);
        }

        [Test]
        public void TestaContémProdutoSemItem()
        {
            CatalogoDeProdutos catálogo = new CatalogoDeProdutos((IProdutoDataAdapter)
                produtoDataMock.MockInstance);

            Assert.IsFalse(catálogo.ContémProduto("00001"));
        }

        [Test]
        public void TestaContémProdutoComItem()
        {
            CatalogoDeProdutos catálogo = new CatalogoDeProdutos((IProdutoDataAdapter)
                produtoDataMock.MockInstance);

            Produto produto = new Produto("00001", "Desodorante", 9.99m);
            produtoDataMock.ExpectAndReturn("ObterProduto", produto, produto.ItemID);

            Assert.IsTrue(catálogo.ContémProduto("00001"));
            produtoDataMock.Verify();
        }
    }
}
